import { observe } from "./observer.js";
import Watcher from "./watcher.js";
import Dep from './dep.js'
export function initState(vm) {
  const opts = vm.$options
  if(opts.data) {
    initData(vm);
  }
  if(opts.computed) {
    initComputed(vm)
  }
  if(opts.watch) {
    initWatch(vm)
  }
}

function initData(vm) {
  let data = vm.$options.data
  data = vm._data = typeof data === 'function' ? data.call(vm) : data || {}
  for(let key in data) {
    proxy(vm, '_data', key)
  }
  // 数据观测
  observe(data);
}

// 数据代理
function proxy(object, sourceKey, key) {
  Object.defineProperty(object, key, {
    get: function() {
      console.log('getter', key);
      return object[sourceKey][key]
    },
    set: function(newVal) {
      console.log('setter', key);
      object[sourceKey][key] = newVal
    }
  })
}

function initWatch(vm) {
  let watch = vm.$options.watch
  for (let k in watch) {
    const handler = watch[k]; //用户自定义watch的写法可能是数组 对象 函数 字符串
    if (Array.isArray(handler)) {
      // 如果是数组就遍历进行创建
      handler.forEach((handle) => {
        createWatcher(vm, k, handle);
      });
    } else {
      createWatcher(vm, k, handler);
    }
  }
}
function createWatcher(vm, exprOrFn, handler, options = {}) {
  if (typeof handler === "object") {
    options = handler; //保存用户传入的对象
    handler = handler.handler; //这个代表真正用户传入的函数
  }
  if (typeof handler === "string") {
    //   代表传入的是定义好的methods方法
    handler = vm[handler];
  }
  //   调用vm.$watch创建用户watcher
  return vm.$watch(exprOrFn, handler, options);
}

function initComputed(vm) {
  const computed = vm.$options.computed
  const watchers = (vm._computedWatchers = {})
  for(let k in computed) {
    const userDef = computed[k]
    const getter = typeof userDef === 'function' ? userDef : userDef.get
    watchers[k] = new Watcher(vm, getter, () => {}, {lazy: true})
    defineComputed(vm, k, userDef)
  }
}

// 定义普通对象用来劫持计算属性
const sharedPropertyDefinition = {
  enumerable: true,
  configurable: true,
  get: () => {},
  set: () => {},
};

function defineComputed(target, key, userDef) {
  if (typeof userDef === "function") {
    // 如果是一个函数  需要手动赋值到get上
    sharedPropertyDefinition.get = createComputedGetter(key);
  } else {
    sharedPropertyDefinition.get = createComputedGetter(key);
    sharedPropertyDefinition.set = userDef.set;
  }
  //   利用Object.defineProperty来对计算属性的get和set进行劫持
  Object.defineProperty(target, key, sharedPropertyDefinition);

}

function createComputedGetter(key) {
  return function () {
    const watcher = this._computedWatchers[key]
    if(watcher) {
      if(watcher.dirty) {
        watcher.evaluate()
        // Dep.target这时指向的都是渲染函数
        if(Dep.target) {
          // 让渲染函数 收集计算属性中的依赖（因为计算属性中的依赖如果模板中没有使用，就不会收集渲染函数watcher）
          // 所以这时需要收集一下
          watcher.depend()
        }
      }
      return watcher.value;
    }
  }
}